/*
 * --------------------------------------------------------------------
 * jQuery-Plugin - selectToUISlider - creates a UI slider component from a select element(s)
 * by Scott Jehl, scott@filamentgroup.com
 * http://www.filamentgroup.com
 * reference article: http://www.filamentgroup.com/lab/update_jquery_ui_16_slider_from_a_select_element/
 * demo page: http://www.filamentgroup.com/examples/slider_v2/index.html
 * 
 * Copyright (c) 2008 Filament Group, Inc
 * Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
 *
 * Usage Notes: please refer to our article above for documentation
 *  
 * --------------------------------------------------------------------
 */


jQuery.fn.selectToUISlider = function(settings) {
    var selects = jQuery(this);

    //accessible slider options
    var options = jQuery.extend({
            labels: 3, //number of visible labels
            tooltip: true, //show tooltips, boolean
            tooltipSrc: "text", //accepts 'value' as well
            labelSrc: "value", //accepts 'value' as well	,
            sliderOptions: null
        },
        settings);


    //handle ID attrs - selects each need IDs for handles to find them
    var handleIds = (function() {
        var tempArr = [];
        selects.each(function() {
            tempArr.push("handle_" + jQuery(this).attr("id"));
        });
        return tempArr;
    })();

    //array of all option elements in select element (ignores optgroups)
    var selectOptions = (function() {
        var opts = [];
        selects.eq(0).find("option").each(function() {
            opts.push({
                value: jQuery(this).attr("value"),
                text: jQuery(this).text()
            });
        });
        return opts;
    })();

    //array of opt groups if present
    var groups = (function() {
        if (selects.eq(0).find("optgroup").size() > 0) {
            var groupedData = [];
            selects.eq(0).find("optgroup").each(function(i) {
                groupedData[i] = {};
                groupedData[i].label = jQuery(this).attr("label");
                groupedData[i].options = [];
                jQuery(this).find("option").each(function() {
                    groupedData[i].options.push({ text: jQuery(this).text(), value: jQuery(this).attr("value") });
                });
            });
            return groupedData;
        } else return null;
    })();

    //check if obj is array
    function isArray(obj) {
        return obj.constructor == Array;
    }

    //return tooltip text from option index
    function ttText(optIndex) {
        return (options.tooltipSrc == "text") ? selectOptions[optIndex].text : selectOptions[optIndex].value;
    }

    //plugin-generated slider options (can be overridden)
    var sliderOptions = {
        step: 1,
        min: 0,
        orientation: "horizontal",
        max: selectOptions.length - 1,
        range: selects.length > 1, //multiple select elements = true
        slide: function(e, ui) { //slide function
            var thisHandle = jQuery(ui.handle);
            //handle feedback 
            var textval = ttText(ui.value);
            thisHandle
                .attr("aria-valuetext", textval)
                .attr("aria-valuenow", ui.value)
                .find(".ui-slider-tooltip .ttContent")
                .text(textval);

            //control original select menu
            var currSelect = jQuery("#" + thisHandle.attr("id").split("handle_")[1]);
            currSelect.find("option").eq(ui.value).attr("selected", "selected");
        },
        values: (function() {
            var values = [];
            selects.each(function() {
                values.push(jQuery(this).get(0).selectedIndex);
            });
            return values;
        })()
    };

    //slider options from settings
    options.sliderOptions = (settings) ? jQuery.extend(sliderOptions, settings.sliderOptions) : sliderOptions;

    //select element change event	
    selects.bind("change keyup click",
        function() {
            var thisIndex = jQuery(this).get(0).selectedIndex;
            var thisHandle = jQuery("#handle_" + jQuery(this).attr("id"));
            var handleIndex = thisHandle.data("handleNum");
            thisHandle.parents(".ui-slider:eq(0)").slider("values", handleIndex, thisIndex);
        });


    //create slider component div
    var sliderComponent = jQuery("<div></div>");

    //CREATE HANDLES
    selects.each(function(i) {
        var hidett = "";

        //associate label for ARIA
        var thisLabel = jQuery("label[for=" + jQuery(this).attr("id") + "]");
        //labelled by aria doesn't seem to work on slider handle. Using title attr as backup
        var labelText = (thisLabel.size() > 0) ? "Slider control for " + thisLabel.text() + "" : "";
        var thisLabelId = thisLabel.attr("id") || thisLabel.attr("id", "label_" + handleIds[i]).attr("id");


        if (options.tooltip == false) {
            hidett = ' style="display: none;"';
        }
        jQuery("<a " +
                'href="#" tabindex="0" ' +
                'id="' +
                handleIds[i] +
                '" ' +
                'class="ui-slider-handle" ' +
                'role="slider" ' +
                'aria-labelledby="' +
                thisLabelId +
                '" ' +
                'aria-valuemin="' +
                options.sliderOptions.min +
                '" ' +
                'aria-valuemax="' +
                options.sliderOptions.max +
                '" ' +
                'aria-valuenow="' +
                options.sliderOptions.values[i] +
                '" ' +
                'aria-valuetext="' +
                ttText(options.sliderOptions.values[i]) +
                '" ' +
                '><span class="screenReaderContext">' +
                labelText +
                "</span>" +
                '<span class="ui-slider-tooltip ui-widget-content ui-corner-all"' +
                hidett +
                '><span class="ttContent"></span>' +
                '<span class="ui-tooltip-pointer-down ui-widget-content"><span class="ui-tooltip-pointer-down-inner"></span></span>' +
                "</span></a>")
            .data("handleNum", i)
            .appendTo(sliderComponent);
    });

    //CREATE SCALE AND TICS

    //write dl if there are optgroups
    if (groups) {
        var inc = 0;
        var scale = sliderComponent.append('<dl class="ui-slider-scale ui-helper-reset" role="presentation"></dl>')
            .find(".ui-slider-scale:eq(0)");
        jQuery(groups).each(function(h) {
            scale.append('<dt style="width: ' +
                (100 / groups.length).toFixed(2) +
                "%" +
                "; left:" +
                (h / (groups.length - 1) * 100).toFixed(2) +
                "%" +
                '"><span>' +
                this.label +
                "</span></dt>"); //class name becomes camelCased label
            var groupOpts = this.options;
            jQuery(this.options).each(function(i) {
                var style = (inc == selectOptions.length - 1 || inc == 0) ? 'style="display: none;"' : "";
                var labelText = (options.labelSrc == "text") ? groupOpts[i].text : groupOpts[i].value;
                scale.append('<dd style="left:' +
                    leftVal(inc) +
                    '"><span class="ui-slider-label">' +
                    labelText +
                    '</span><span class="ui-slider-tic ui-widget-content"' +
                    style +
                    "></span></dd>");
                inc++;
            });
        });
    }
    //write ol
    else {
        var scale = sliderComponent.append('<ol class="ui-slider-scale ui-helper-reset" role="presentation"></ol>')
            .find(".ui-slider-scale:eq(0)");
        jQuery(selectOptions).each(function(i) {
            var style = (i == selectOptions.length - 1 || i == 0) ? 'style="display: none;"' : "";
            var labelText = (options.labelSrc == "text") ? this.text : this.value;
            scale.append('<li style="left:' +
                leftVal(i) +
                '"><span class="ui-slider-label">' +
                labelText +
                '</span><span class="ui-slider-tic ui-widget-content"' +
                style +
                "></span></li>");
        });
    }

    function leftVal(i) {
        return (i / (selectOptions.length - 1) * 100).toFixed(2) + "%";

    }


    //show and hide labels depending on labels pref
    //show the last one if there are more than 1 specified
    if (options.labels > 1)
        sliderComponent
            .find(".ui-slider-scale li:last span.ui-slider-label, .ui-slider-scale dd:last span.ui-slider-label")
            .addClass("ui-slider-label-show");

    //set increment
    var increm = Math.max(1, Math.round(selectOptions.length / options.labels));
    //show em based on inc
    for (var j = 0; j < selectOptions.length; j += increm) {
        if ((selectOptions.length - j) > increm) { //don't show if it's too close to the end label
            sliderComponent
                .find(".ui-slider-scale li:eq(" +
                    j +
                    ") span.ui-slider-label, .ui-slider-scale dd:eq(" +
                    j +
                    ") span.ui-slider-label").addClass("ui-slider-label-show");
        }
    }

    //style the dt's
    sliderComponent.find(".ui-slider-scale dt").each(function(i) {
        jQuery(this).css({
            'left': ((100 / (groups.length)) * i).toFixed(2) + "%"
        });
    });


    //inject and return 
    sliderComponent
        .insertAfter(jQuery(this).eq(this.length - 1))
        .slider(options.sliderOptions)
        .attr("role", "application")
        .find(".ui-slider-label")
        .each(function() {
            jQuery(this).css("marginLeft", -jQuery(this).width() / 2);
        });

    //update tooltip arrow inner color
    sliderComponent.find(".ui-tooltip-pointer-down-inner").each(function() {
        var bWidth = jQuery(".ui-tooltip-pointer-down-inner").css("borderTopWidth");
        var bColor = jQuery(this).parents(".ui-slider-tooltip").css("backgroundColor");
        jQuery(this).css("border-top", bWidth + " solid " + bColor);
    });

    var values = sliderComponent.slider("values");

    if (isArray(values)) {
        jQuery(values).each(function(i) {
            sliderComponent.find(".ui-slider-tooltip .ttContent").eq(i).text(ttText(this));
        });
    } else {
        sliderComponent.find(".ui-slider-tooltip .ttContent").eq(0).text(ttText(values));
    }

    return this;
}
